﻿using Autofac;
using Rapattern.interfaces;
using Rapattern.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// http://niuyi.github.io/blog/2012/04/06/autofac-by-unit-test/
/// http://www.cnblogs.com/jys509/p/4649798.html
/// https://autofac.org/
/// http://autofac.readthedocs.io/en/latest/getting-started/index.html
/// https://autofac.org/apidoc/html/62C594FF.htm
/// https://github.com/autofac/Autofac
/// </summary>
namespace Rapattern.App
{
    /// <summary>
    /// IRegistrationBuilder.InstancePerDependency:对每一个依赖或每一次调用创建一个新的唯一的实例。这也是默认的创建实例的方式。
    /// IRegistrationBuilder.InstancePerLifetimeScope:在一个生命周期域中，每一个依赖或调用创建一个单一的共享的实例，且每一个不同的生命周期域，实例是唯一的，不共享的。
    /// IRegistrationBuilder.InstancePerMatchingLifetimeScope:在一个做标识的生命周期域中，每一个依赖或调用创建一个单一的共享的实例。打了标识了的生命周期域中的子标识域中可以共享父级域中的实例。若在整个继承层次中没有找到打标识的生命周期域，则会抛出异常：DependencyResolutionException。
    /// IRegistrationBuilder.InstancePerOwned:在一个生命周期域中所拥有的实例创建的生命周期中，每一个依赖组件或调用Resolve()方法创建一个单一的共享的实例，并且子生命周期域共享父生命周期域中的实例。若在继承层级中没有发现合适的拥有子实例的生命周期域，则抛出异常：DependencyResolutionException。
    /// IRegistrationBuilder.SingleInstance:每一次依赖组件或调用Resolve()方法都会得到一个相同的共享的实例。其实就是单例模式。
    /// IRegistrationBuilder.InstancePerHttpRequest:在一次Http请求上下文中,共享一个组件实例。仅适用于asp.net mvc开发。
    /// IRegistrationBuilder.OnActivating:在注册组件使用之前会被调用 例：OnActivating(p=>p.Instance.Method())
    /// IRegistrationBuilder.OnActivated:在实例化之后会被调用
    /// IRegistrationBuilder.OnRelease:在组件释放之后会被调用 
    /// </summary>
    public class AutofacConfig
    {
        public static void ConfigureContainer()
        {
            var builder = new ContainerBuilder();

            // 使用RegisterType进行注册
            //builder.RegisterType<EmployeeRepository>();
            //var myClass = MemoryInfo.StoreContainer.Resolve<EmployeeRepository>();
            // 注册为接口
            //builder.Register(c => new EmployeeRepository()).As<IEmployeeRepository>();
            //var myClass = MemoryInfo.StoreContainer.Resolve<IEmployeeRepository>();
            // 使用lambda表达式进行注册
            //builder.Register(c => new EmployeeRepository());
            //var myClass = MemoryInfo.StoreContainer.Resolve<EmployeeRepository>();
            // 带构造参数的注册
            //builder.Register(c => new MyParameter());
            //builder.Register(c => new MyClass(c.Resolve<MyParameter>()));
            //var myClass = MemoryInfo.StoreContainer.Resolve<EmployeeRepository>();
            // 带属性赋值的注册
            //builder.Register(c => new MyProperty());
            //builder.Register(c => new MyClass(){
            //    Property = c.Resolve<MyProperty>()
            //});
            //var myClass = MemoryInfo.StoreContainer.Resolve<EmployeeRepository>();
            // Autofac分离了类的创建和使用，这样可以根据输入参数（NamedParameter）动态的选择实现类
            //builder.Register<IRepository>((c, p) =>{
            //    var type = p.Named<string>("type");
            //    if (type == "test")
            //    {
            //        return new TestRepository();
            //    }
            //    else
            //    {
            //        return new DbRepository();
            //    }
            //}).As<IRepository>();
            //var repository = MemoryInfo.StoreContainer.Resolve<IRepository>(new NamedParameter("type", "test"));
            // AufoFac也可以用一个实例来注册，比如用在单例模式情况下：
            //builder.RegisterInstance(MyInstance.Instance).ExternallyOwned();
            //var myInstance1 = MemoryInfo.StoreContainer.Resolve<MyInstance>();
            //var myInstance2 = MemoryInfo.StoreContainer.Resolve<MyInstance>();
            // 注册open generic类型
            //builder.RegisterGeneric(typeof(MyList<>));
            //var myIntList = MemoryInfo.StoreContainer.Resolve<MyList<int>>();
            //var myStringList = MemoryInfo.StoreContainer.Resolve<MyList<string>>();
            // 对于同一个接口，后面注册的实现会覆盖之前的实现
            //builder.RegisterType<DbRepository>().As<IRepository>();
            //builder.RegisterType<TestRepository>().As<IRepository>();
            //var repository = MemoryInfo.StoreContainer.Resolve<IRepository>();
            // 如果不想覆盖的话，可以用PreserveExistingDefaults，这样会保留原来注册的实现。
            //builder.RegisterType<DbRepository>().As<IRepository>();
            //builder.RegisterType<TestRepository>().As<IRepository>().PreserveExistingDefaults();
            //var repository = MemoryInfo.StoreContainer.Resolve<IRepository>();
            // 可以用Name来区分不同的实现，代替As方法
            //builder.RegisterType<DbRepository>().Named<IRepository>("DB");
            //builder.RegisterType<TestRepository>().Named<IRepository>("Test");
            //var dbRepository = MemoryInfo.StoreContainer.ResolveNamed<IRepository>("DB");
            //var testRepository = MemoryInfo.StoreContainer.ResolveNamed<IRepository>("Test");
            // 如果一个类有多个构造函数的话，可以在注册时候选择不同的构造函数
            //builder.RegisterType<MyParameter>();
            //builder.RegisterType<MyClass>().UsingConstructor(typeof(MyParameter));
            //var myClass = MemoryInfo.StoreContainer.Resolve<MyClass>();
            // AutoFac可以注册一个Assemble下所有的类，当然，也可以根据类型进行筛选
            builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(EmployeeRepository))).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces();
            MemoryInfo.StoreContainer = builder.Build();
            //var repository = MemoryInfo.StoreContainer.Resolve<IEmployeeRepository>();
        }
    }
}
